package cn.lyjuan.archetypes.bms.web.config;

import cn.lyjuan.archetypes.bms.web.property.SysProperties;
import cn.lyjuan.archetypes.bms.web.service.ActionService;
import cn.lyjuan.archetypes.bms.web.service.ManageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.util.List;

/**
 * Created by chad on 2016/8/23.
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    private SysProperties sysProperties;

    @Autowired
    private ActionService actionService;

    @Autowired
    private ManageService manageService;

    /**
     * 匿名用户信息
     */
    public static final Integer GUEST_MANAGER_ID = 1;
    public static final String GUEST_NAME = "guest";

    public static final String LOGIN_PAGE = "/login";
    public static final String LOGIN_PROCESS = "/loginSubmit";
    public static final String LOGIN_SUCC = "/loginSucc";
    public static final String LOGIN_FAIL = "/loginFail";
    public static final String LOGOUT_PROCESS = "/logout";
    public static final String LOGOUT_SUCC = LOGIN_PAGE;
    /**
     * 登录验证码
     */
    public static final String LOGIN_CODE = "/loginCode";
    /**
     * 首页
     */
    public static final String INDEX = "/";

    /**
     * 请求后缀
     */
    private String urlSuf = "";

    @Autowired
    public SecurityConfig(SysProperties sysProperties)
    {
        this.sysProperties = sysProperties;
        this.urlSuf = sysProperties.getUrlSuffix();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder()
    {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        return passwordEncoder;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        // 自定义用户及权限服务
        auth.userDetailsService(new UserDetailsServiceImpl(manageService, actionService))
                //密码加密方式
                .passwordEncoder(passwordEncoder());;
    }

    @Override
    public void configure(WebSecurity web) throws Exception
    {
        // 登陆页都可以访问
//        web.ignoring().antMatchers("/images/**", "/css/**", "/js/**", "/404.html", "/500.html");
        // 如果不加这个，进入登陆页面时，会经过Security跳转，不能带参数
        web.ignoring()
                .mvcMatchers(LOGIN_PAGE)
                .mvcMatchers(LOGIN_PROCESS)
                .mvcMatchers(LOGIN_FAIL)
                .mvcMatchers(LOGIN_CODE)
                .mvcMatchers(LOGIN_SUCC)
                .mvcMatchers("/static/**")

                .antMatchers("/html/**")
                .antMatchers("/images/**")
                .antMatchers("/font/**")
                .antMatchers("/css/**")
                .antMatchers("/js/**")

                .antMatchers("/layui/**")
        // todo 后期修改可自定义添加
        ;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
                registry
                = http.csrf().disable()
                .headers().frameOptions().sameOrigin()
                .and()
                // todo 未使用服务端验证码
                // 在用户名密码验证的 Filter 前加验证码Filter
//                .addFilterBefore(new LoginCodeFilter(LOGIN_PROCESS + urlSuf,
//                                LOGIN_FAIL + urlSuf),
//                        UsernamePasswordAuthenticationFilter.class)
                .formLogin()
                    .loginPage(LOGIN_PAGE + urlSuf)
                    .successForwardUrl(LOGIN_SUCC + urlSuf)
                    .loginProcessingUrl(LOGIN_PROCESS + urlSuf)
                    .failureUrl(LOGIN_FAIL + urlSuf)
                .and()
                    .logout()
                    .logoutUrl(LOGOUT_PROCESS + urlSuf)
                    .logoutSuccessUrl(LOGOUT_SUCC + urlSuf)
                .and()
                .authorizeRequests()
                //1. 能找到匹配的URL时，不使用anyRequest
//                .antMatchers("/test/test.mg").hasAuthority("test_test")
//                .anyRequest().hasAuthority(UserDetailsServiceImpl.SUPPER_ADMIN)
                //2. 同样的URL匹配规则时，后面的会覆盖前面的
//                .antMatchers("/test/test.mg").hasAuthority("test/test")
//                .antMatchers("/test/test.mg").hasAuthority(UserDetailsServiceImpl.SUPPER_ADMIN)
                ;

        // 所有已登录用户可访问首页，资源文件
        registry.mvcMatchers(INDEX).authenticated();

        // 查询所有请求
        List<String> list = actionService.queryAllActions();

        if (null != list && !list.isEmpty())
        {
            for (String a : list)// 后缀为 自定义配置的
            {
                registry.mvcMatchers("/" + a)
                        .hasAuthority(a);
            }
        }

        // 来宾请求
        list = actionService.queryAllActions(GUEST_MANAGER_ID);
        if (null != list && !list.isEmpty())
        {
            for (String a : list)// 后缀为 自定义配置的
            {
                registry.mvcMatchers("/" + a)
                        .permitAll();
            }
        }

        // 剩余的请求拒绝
        registry.anyRequest().denyAll();
    }
}
